import base64
import mimetypes
import os
import re
import shutil
import time
import uuid
from pathlib import Path

import html2text
from bs4 import BeautifulSoup
from bs4.element import Tag

from app.config import settings


def convert_html_to_md(html_path, md_path, base_dir=None):
    """转换单个 HTML 文件为 Markdown, 图片转为 Base64"""
    # 设置 HTML2Text 转换器
    h = html2text.HTML2Text()
    h.body_width = 0  # 禁用自动换行
    h.wrap_links = False  # 对链接不进行换行处理
    h.skip_internal_links = True  # 跳过内部链接
    h.ignore_images = False  # 确保不忽略图片

    # 读取 HTML 内容
    with open(html_path, "r", encoding="utf-8", errors="ignore") as f:
        html_content = f.read()

    # 转换为 Markdown
    md_content = h.handle(html_content)

    # 处理图片：转换为 Base64
    md_content = replace_images_with_base64(md_content, md_path, base_dir)

    # 确保输出目录存在
    os.makedirs(os.path.dirname(md_path), exist_ok=True)

    # 写入 Markdown 文件
    with open(md_path, "w", encoding="utf-8") as f:
        f.write(md_content)


def replace_images_with_base64(md_content, md_path, base_dir):
    """将 Markdown 中的图片引用替换为 Base64 格式"""
    # 找到所有图片引用
    img_pattern = r"!\[([^\]]*)\]\(([^)]+)\)"
    matches = list(re.finditer(img_pattern, md_content))

    if not matches:
        return md_content

    # 获取MD文件所在目录
    md_dir = os.path.dirname(md_path)

    for match in matches:
        alt_text = match.group(1)
        img_path = match.group(2)

        # 尝试解析图片路径
        img_abs_path = resolve_image_path(img_path, md_dir, base_dir)
        if not img_abs_path:
            continue
        # 读取图片并转换为 Base64
        try:
            with open(img_abs_path, "rb") as img_file:
                img_data = img_file.read()
                base64_data = base64.b64encode(img_data).decode("utf-8")
                mime_type = mimetypes.guess_type(img_abs_path)[0] or "image/png"
                base64_img = f"data:{mime_type};base64,{base64_data}"

                # 替换 Markdown 中的图片引用
                md_content = md_content.replace(
                    f"![{alt_text}]({img_path})", f"![{alt_text}]({base64_img})"
                )
        except Exception as e:
            print(f"无法处理图片 {img_abs_path}: {e}")

    return md_content


def resolve_image_path(img_path, md_dir, base_dir):
    """解析图片的绝对路径：先查HTML目录, 再查根目录"""
    # 处理绝对路径
    if os.path.isabs(img_path):
        if os.path.isfile(img_path):
            return img_path
        return None

    # 处理网络路径
    if img_path.startswith(("http://", "https://", "//")):
        return None

    # 1. 首先尝试相对于HTML文件目录
    candidate_path = os.path.normpath(os.path.join(md_dir, img_path))
    if os.path.isfile(candidate_path):
        return candidate_path

    # 2. 如果找不到, 尝试相对于根目录(base_dir)
    if base_dir:
        candidate_path = os.path.normpath(os.path.join(base_dir, img_path))
        if os.path.isfile(candidate_path):
            return candidate_path

    return None


def process_directory(input_path):
    input_path = os.path.abspath(input_path)
    input_base = os.path.basename(input_path)
    parent_dir = os.path.dirname(input_path)
    # 1. 在input_path同级创建output_path, 名称为input_path+时间戳
    ts = time.strftime("%Y%m%d_%H%M%S")
    output_base = f"{input_base}_{ts}"
    output_path = os.path.join(parent_dir, output_base)
    # 2. 复制 input_path目录到output_path
    shutil.copytree(input_path, output_path)
    # 3. 修改 html 内容中的链接为相对路径
    for root, dirs, files in os.walk(output_path):
        for file in files:
            if file.lower().endswith(".html") or file.lower().endswith(".htm") or file.lower().endswith(".mhtml"):
                file_path = os.path.join(root, file)
                with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
                    html_content = f.read()
                soup = BeautifulSoup(html_content, "html.parser")
                attrs = ["href", "src"]
                for tag in soup.find_all(
                        lambda tag: any(tag.has_attr(attr) for attr in attrs)
                ):
                    if not isinstance(tag, Tag):
                        continue
                    for attr in attrs:
                        if tag.has_attr(attr):
                            val = str(tag[attr])
                            if input_base in val:
                                tag[attr] = val.replace(input_base, output_base, 1)
                            if val.startswith("/"):
                                # 当前文件相对于output_path的相对路径
                                relative_path = os.path.relpath(
                                    output_path, file_path
                                )
                                tag[attr] = str(tag[attr]).replace("/", f"{relative_path}/", 1)
                with open(file_path, "w", encoding="utf-8") as f:
                    f.write(str(soup))
    # 4. 把 html 文件转为 md
    for root, dirs, files in os.walk(output_path):
        for file in files:
            if file.lower().endswith(".html") or file.lower().endswith(".htm") or file.lower().endswith(".mhtml"):
                file_path = os.path.join(root, file)
                md_path = file_path.replace(".html", ".md").replace(".htm", ".md").replace(".mhtml", ".md")
                convert_html_to_md(file_path, md_path, base_dir=output_path)
                os.remove(file_path)
    # 5. 遍历output_path目录下文件, 只保留 md 文件
    for root, dirs, files in os.walk(output_path):
        for file in files:
            if not file.lower().endswith(".md"):
                os.remove(os.path.join(root, file))
    return output_path


def save_pic_nginx(path: Path):
    """
    1. 接收Path对象，判断该文件是否为文件或者为文件夹
    2. 在nginx_static_dir目录下创建该文件的父目录名的文件夹
    3. 是文件则遍历该文件，找该 md文件中图片的base64 的内容，保存在第二步创建的文件夹中，替换该图片 base64 内容为 nginx path
    4. 是文件夹则递归处理所有 md 文件
    """

    def process_md(md_file: Path, target_dir: str, nginx_url_prefix: str):
        with open(md_file, 'r', encoding='utf-8') as f:
            content = f.read()

        # 匹配 base64 图片
        def save_and_replace(match):
            mime = match.group(1)
            base64_str = match.group(2)
            ext = mime.split('/')[-1]
            img_bytes = base64.b64decode(base64_str)
            img_name = f"img_{uuid.uuid4().hex[:8]}.{ext}"
            img_path = os.path.join(target_dir, img_name)
            os.makedirs(target_dir, exist_ok=True)
            with open(img_path, 'wb') as imgf:
                imgf.write(img_bytes)
            # 返回 nginx 路径
            nginx_path = f"{nginx_url_prefix}/{target_dir.lstrip("nginx/")}/{img_name}"
            return f"![]({nginx_path})"

        # 替换所有 base64 图片
        new_content = re.sub(r'!\[.*?\]\(data:(image/[^;]+);base64,([A-Za-z0-9+/=]+)\)', save_and_replace, content)
        with open(md_file, 'w', encoding='utf-8') as f:
            f.write(new_content)

    nginx_static_dir = settings.nginx_static_dir
    nginx_url_prefix = settings.nginx_url_prefix
    if path.is_file():
        parent_name = path.parent.name
        target_dir = os.path.join(nginx_static_dir, parent_name)
        process_md(path, target_dir, nginx_url_prefix)
    elif path.is_dir():
        parent_name = f"{path.parent.name}/{path.name}"
        target_dir = os.path.join(nginx_static_dir, parent_name)
        for root, dirs, files in os.walk(path):
            for file in files:
                if file.lower().endswith('.md'):
                    md_file = Path(root) / file
                    process_md(md_file, target_dir, nginx_url_prefix)


def html_convert_to_md(file_path: Path):
    if file_path.is_file():
        base_dir = os.path.dirname(file_path)
        # basename = os.path.basename(file_path)
        basename, _ = os.path.splitext(os.path.basename(file_path))
        md_path = os.path.join(base_dir, f"{basename}.md")
        convert_html_to_md(file_path, md_path, base_dir=base_dir)
        save_pic_nginx(Path(md_path))
        return md_path
    elif file_path.is_dir():
        md_path = process_directory(file_path)
        save_pic_nginx(Path(md_path))
        return md_path
